前情提要:
昨天講了component複雜的生命週期,其實主要概念只有可以在componentDidMount、
componentDidUpdate和componentWillUnmount做一些非同步處理和事件監聽行為(如:resize或scroll)。
今天我們就來點互動吧!
說是這麼說,但其實昨天的codepen範例和前天的計數器,我都默默偷渡click event了。ˊ_>ˋ
不過如果不用event去更改state,那怎麼介紹state更新還有生命週期的變換,筆述說明的話也太無趣了吧!
在知道使用方式後,我們今天就來了解還有哪些細節需要注意吧!
使用React element處理事件(event)和在DOM element處理event的行為其實是非常相似的(難怪用起來沒有什麼不適感(?!),以下列出差異:
camelCase
命名,不是lowercase。如:
function
作為事件處理,而不是使用string<button onclick="handleClick()">
Activate Lasers
</button>
在React的細微差異
<button onClick={handleClick}>
Activate Lasers
</button>
preventDefault()
<a href="#" onclick="console.log('The link was clicked.'); return false">
Click me
</a>
React使用情況
function ActionLink() {
function handleClick(e) {
e.preventDefault();
console.log('The link was clicked.');
}
return (
<a href="#" onClick={handleClick}>
Click me
</a>
);
}
在上述的例子裡,e
是一個合成事件(synthetic event)。React根據W3C規範定義了這些合成事件(synthetic event),所以我們不用擔心跨瀏覽器相容性。(想知道更多嗎?左轉SyntheticEvent)。接著是處理event的method綁定(bind)this的二三事。等等,這個不也是前天的內容嗎?果然component一家親,圈子很小相見容易。我們再來複習一下有哪些綁定方法吧! ╮( ̄▽ ̄"")╭
Bind in Constructor (ES2015)
class Foo extends Component {
constructor(props) {
super(props);
this.handleClick = this.handleClick.bind(this);
}
handleClick() {
console.log('Click happened');
}
render() {
return <button onClick={this.handleClick}>Click Me</button>;
}
}
Class Properties (Stage 3 Proposal)
class Foo extends Component {
// Note: 此語法還是實驗性,尚未標準化
handleClick = () => {
console.log('Click happened');
}
render() {
return <button onClick={this.handleClick}>Click Me</button>;
}
}
以下兩種bind方法會在每次render的時候就建立一個新的function,有效能上的影響
Bind in Render
class Foo extends Component {
handleClick() {
console.log('Click happened');
}
render() {
return <button onClick={this.handleClick.bind(this)}>Click Me</button>;
}
}
Arrow Function in Render
class Foo extends Component {
handleClick() {
console.log('Click happened');
}
render() {
return <button onClick={() => this.handleClick()}>Click Me</button>;
}
}
傳遞額外的參數到事件處理器
接著,情境題來了。如果我有一個待辦事項列表(To-Do List),每項資料都有button讓我刪除該筆資料,我想透過id刪掉該筆資料,該怎麼做?
雖然在上面的幾種方法有提到如果在render method內bind this,會在每次re-render的時候都建立一個新function,但如果我們想要多傳其他資料給function內使用,也只能仰賴它們了,實際用法如下:
<button onClick={(e) => this.deleteRow(id, e)}>Delete Row</button>
<button onClick={this.deleteRow.bind(this, id)}>Delete Row</button>
那我們來練習用這個方法刪除清單上的項目吧!
執行步驟如下:
Warning: Each child in an array or iterator should have a unique "key" prop.
,提醒我們array內的每個react element都需要設定key
值import React, { Component } from "react";
import data from "../../data";
class List extends Component {
constructor(props) {
super(props);
this.state = {
data
};
}
deleteItem(id) {
this.setState({
data: this.state.data.filter(data => data.id !== id)
});
}
render() {
return this.state.data.map(({ id, greeting }) => (
<li key={id}>
{greeting}
<button onClick={() => this.deleteItem(id)}>刪除</button>
</li>
));
}
}
export default List;
import React from "react";
import ReactDOM from "react-dom";
import List from "./src/components/list";
const App = () => {
return (
<ul>
<List />
</ul>
);
};
ReactDOM.render(<App />, document.getElementById("app"));
在terminal上執行yarn start
操作畫面如下:
完整程式碼請參考github
總結今日:
preventDefault()
本日完結,大家週末愉快!
果然component一家親,圈子很小相見容易。
太認同這句話了,每次寫寫都會覺得一直在講差不多的東西
哈哈!常常寫一寫寫到自我迷失(欸
一起加油!